package com.tarena.luban.worker.server.repository.impl;

import com.tarena.luban.worker.server.bo.WorkerBO;
import com.tarena.luban.worker.server.dao.WorkerDao;
import com.tarena.luban.worker.server.repository.CacheRepository;
import com.tarena.luban.worker.server.repository.WorkerRepository;
import com.tarena.luban.worker.server.repository.converter.WorkerConverter;
import com.tarena.tp.luban.worker.po.Worker;
import com.tarena.tp.luban.worker.server.dto.param.WorkerCreateParam;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Repository;

import java.util.Random;
import java.util.concurrent.TimeUnit;

@Repository
public class WorkerRepoImpl extends CacheRepository<WorkerBO> implements WorkerRepository {
    @Autowired(required = false)
    private WorkerDao workerDao;
    @Override
    public void deleteWorkerByUserId(Long userId) {
        //先删除缓存
        String key="luban:worker:"+userId;
        del(key);
        //删除 userId绑定worker数据 对数据库做了写
        workerDao.delete(userId);
        //缓存也要删除
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        del(key);
    }

    /**
     * dao层入参和出参 如果是数据对象一定是DO/PO/ENTITY对象
     * @return
     */
    @Autowired
    private WorkerConverter workerConverter;
    @Override
    public Long saveWorker(WorkerCreateParam workerCreateParam) {
        //1. 类型转化 BeanUtils status auditStatus certStatus 6个通用字段
        Worker worker = workerConverter.param2po(workerCreateParam);
        //2. insert新增
        workerDao.insert(worker);
        //这个worker的id是新增结束之后 mybatis框架回调补充
        return worker.getId();
    }

    @Override
    public WorkerBO getWorkerByUserId(Long userId){
        //TODO 布隆过滤器 提前存储当前数据所有worker数据 批量预热 增量预热 每次新增一个师傅都在布隆存储数据
        String key="luban:worker:"+userId;
        Boolean hasKey = redisTemplate.hasKey(key);
        if (hasKey){
            return get(key);
        }else {
            //为了防止大量请求 未命中同一个热点数据 导致缓存击穿出现,加锁
            String lockKey=key+".lock";
            boolean tryLock = tryLock(lockKey);
            if(tryLock){
                Worker worker=workerDao.selectByUserId(userId);
                WorkerBO workerBO = workerConverter.po2bo(worker);
                //放缓存一份 一般都需要设置超时时间
                set(key,workerBO,60*60*5+new Random().nextLong()%(60*60*5),TimeUnit.SECONDS);
                //手动释放锁
                del(lockKey);
                return workerBO;
            }else {
                //没抢到锁 在这个业务中重新抢锁 重新查数据
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //不管拿到还是拿不到 都从缓存 大概率是可以拿到的
                return get(key);
            }
        }
    }
}
